package com.evil.common.core.util;

import cn.hutool.core.collection.CollectionUtil;
import com.evil.common.core.enums.SwitchEnum;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * 数组比较工具类
 *
 * @author liyang
 * @date 2025-03-07 13:18
 */
public class ArrayCompareUtil {

    /**
     * 比较数据库实体列表与参数列表
     *
     * @param entityList        数据库实体列表
     * @param dtoList           参数列表
     * @param getEntityId       获取数据库实体ID
     * @param getDtoId          获取参数ID
     * @param getEntityIsDelete 获取数据库实体删除状态
     * @param setEntityIsDelete 设置数据库实体删除状态
     * @param modifyOrAddFunc   更新或新增回调
     * @param deletedFunc       删除回调
     * @param createFunc        创建新实体
     * @param <ENTITY>          数据库实体
     * @param <DTO>             参数
     * @param <ID>              ID
     * @return 收集需要改动列表
     */
    public static <ENTITY, DTO, ID> List<ENTITY> compare(Collection<ENTITY> entityList,
                                                         Collection<DTO> dtoList,
                                                         Function<ENTITY, ID> getEntityId,
                                                         Function<DTO, ID> getDtoId,
                                                         Function<ENTITY, Integer> getEntityIsDelete,
                                                         BiConsumer<ENTITY, Integer> setEntityIsDelete,
                                                         ModifyOrAddFunc<ENTITY, DTO, Boolean> modifyOrAddFunc,
                                                         DeleteFunc<ENTITY, Boolean> deletedFunc,
                                                         CreateFunc<DTO, ENTITY> createFunc) {
        // 收集需要改动列表
        List<ENTITY> modifies = new ArrayList<>();
        // 参数map
        Map<ID, DTO> dtoMap = StreamUtil.toMapK(dtoList, getDtoId);
        // 存在IDS
        Map<ID, ENTITY> entityMap = new HashMap<>();
        // 处理数据库存在的
        if (CollectionUtil.isNotEmpty(entityList)) {
            entityList.forEach(entity -> {
                ID entityId = getEntityId.apply(entity);
                // 记录存在ID
                entityMap.put(entityId, entity);
                // 获取数据库中删除状态
                Integer entityIsDelete = getEntityIsDelete.apply(entity);
                // 判断数据库中是否已删除
                boolean isDeleted = SwitchEnum.isOpen(entityIsDelete);
                // 是否需要收集
                boolean needModify = false;
                // 参数中存在 ==> 更新操作/新增操作（仅限 删除标记还原为未删除）
                if (dtoMap.containsKey(entityId)) {
                    DTO dto = dtoMap.get(entityId);
                    // 标识未删除
                    if (isDeleted) {
                        needModify = true;
                        setEntityIsDelete.accept(entity, SwitchEnum.NO.getId());
                    }
                    // 未删除回调（数据库本来已删除，那么这里输入新增操作）
                    if (null != modifyOrAddFunc) {
                        if (modifyOrAddFunc.callback(entity, dto, isDeleted)) {
                            needModify = true;
                        }
                    }
                }
                // 参数中不存在 ==> 删除操作
                else {
                    // 标识已删除
                    if (!isDeleted) {
                        needModify = true;
                        setEntityIsDelete.accept(entity, SwitchEnum.YES.getId());
                    }
                    // 会删除回调
                    if (null != deletedFunc) {
                        if (deletedFunc.callback(entity, !isDeleted)) {
                            needModify = true;
                        }
                    }
                }
                // 收集
                if (needModify) modifies.add(entity);
            });
        }
        // 处理参数存在的
        if (CollectionUtil.isNotEmpty(dtoList)) {
            dtoList.forEach(dto -> {
                ID id = getDtoId.apply(dto);
                ENTITY entity;
                // 数据库中不存在 ==> 新增操作（仅限数据库从未出现过的）
                if (!entityMap.containsKey(id)) {
                    // 创建新的entity
                    entity = createFunc.callback(dto);
                    setEntityIsDelete.accept(entity, SwitchEnum.NO.getId());
                    // 未删除回调（数据库本来已删除，那么这里输入新增操作）
                    if (null != modifyOrAddFunc) {
                        modifyOrAddFunc.callback(entity, dto, true);
                    }
                    modifies.add(entity);
                }
            });
        }
        return modifies;
    }

    /**
     * 更新或新增回调
     *
     * @param <ENTITY>  实体
     * @param <DTO>     参数
     * @param <Boolean> 是否新增
     */
    @FunctionalInterface
    public interface ModifyOrAddFunc<ENTITY, DTO, Boolean> {
        Boolean callback(ENTITY entity, DTO dto, Boolean add);
    }

    /**
     * 删除回调
     *
     * @param <ENTITY>  实体
     * @param <Boolean> 是否删除
     */
    @FunctionalInterface
    public interface DeleteFunc<ENTITY, Boolean> {
        Boolean callback(ENTITY entity, Boolean add);
    }

    /**
     * 创建回调
     *
     * @param <DTO>    参数
     * @param <ENTITY> 实体
     */
    @FunctionalInterface
    public interface CreateFunc<DTO, ENTITY> {
        ENTITY callback(DTO dto);
    }
}
